/**
 * GamesLibraryServiceImpl.java
 * 作者：苏新阳
 * 完成度：进行中
 * 最后修改日期：2023-7-3 19:22
 */
package com.gomokult.service.impl;

import com.gomokult.dao.DisplayedGameDAO;
import com.gomokult.dao.GameDAO;
import com.gomokult.dao.GameLikeDAO;
import com.gomokult.dao.UserDAO;
import com.gomokult.dao.impl.DisplayedGameDAOImpl;
import com.gomokult.dao.impl.GameDAOImpl;
import com.gomokult.dao.impl.GameLikeDAOImpl;
import com.gomokult.dao.impl.UserDAOImpl;
import com.gomokult.exception.DuplicatedOperationException;
import com.gomokult.exception.IllegalOperationException;
import com.gomokult.exception.InvalidIDException;
import com.gomokult.exception.NoSuchPageException;
import com.gomokult.service.GamesLibraryService;
import com.gomokult.entity.Game;
import com.gomokult.entity.GameDisplayInfo;
import java.sql.Timestamp;
import java.util.List;

public class GamesLibraryServiceImpl implements GamesLibraryService {
	private GamesLibraryServiceImpl() {}
	private static final GamesLibraryServiceImpl singleton = new GamesLibraryServiceImpl();
	public static GamesLibraryServiceImpl getSingleton() { return singleton; }
    private GameDAO gameDAO=GameDAOImpl.getSingleton();//注入gameDAO
    private GameLikeDAO gameDAOLike=GameLikeDAOImpl.getSingleton();//注入gameDAO
    private DisplayedGameDAO displayedGameDAO= DisplayedGameDAOImpl.getSingleton();//注入dispalyGameDAO
    private UserDAO userDAO= UserDAOImpl.getSingleton();//注入UserDao

    @Override
    public Game getGame(int gameID) throws InvalidIDException {//获取根据gameID获取game实体
        Game game = gameDAO.getGame(gameID);
        if (game == null) {
            throw new InvalidIDException();
        }
        return game;
    }

    //需要提交到数据库的对局数据。需要注意的是：该{@code Game}对象只是作为提交数据的载体，其中的{@code gameID}字段将被忽略，可以填写为任意值，真正的主键由数据库负责生成维护
    @Override
    public int submitGame(Game gameData){
        return gameDAO.insertGame(gameData);
    }

    //根据点赞状态，判断是否将用户ID{@code userID},对局ID{@code gameID}插入到表中
    @Override
    public boolean setLikeState(int userID, int gameID, boolean liked) throws InvalidIDException {
        boolean record = gameDAOLike.selectLikeRecord(userID, gameID);

        if (record == liked ) {

            return true;
        }
        else {
            if(liked==false&&record==true){
                gameDAOLike.deleteLikeRecord(userID,gameID);
            }
            else if(liked==true&&record==false){
                gameDAOLike.insertLikeRecord(userID, gameID);
            }
        }

        return false;
    }

    //判断用户是否点赞该对局
    @Override
    public boolean getLikeState(int userID, int gameID) throws InvalidIDException {
        boolean record = gameDAOLike.selectLikeRecord(userID, gameID);//获取
        if (record == false) {
            throw new InvalidIDException();
        }
        return record;
    }

    //转换对局状态，true变为false，false变为true
    @Override
    public boolean switchLikeState(int userID, int gameID) throws InvalidIDException {
        boolean record = gameDAOLike.selectLikeRecord(userID, gameID);
        if(record==true) {
            gameDAOLike.deleteLikeRecord(userID,gameID);
            return false;
        }
        else{
            gameDAOLike.insertLikeRecord(userID, gameID);
            return true;
        }
    }

    @Override
    public int getLikesCount(int gameID) throws InvalidIDException {
        return gameDAOLike.selectLikeRecord(gameID);
    }

    //获取数据库中的所有对局的个数
    @Override
    public int getGamesCount() {
        return gameDAO.getGamesCount();
    }

    //获取当前数据库中对局数量换成页数的int数据
    @Override
    public int getGamePagesCount() {
        int a = gameDAO.getGamesCount();
        if(a==0)
            return 1;
        return (gameDAO.getGamesCount() + 19) / 20;
    }

    @Override
    public int getGamePagesCount(String email, Timestamp startDate, Timestamp endDate) {

        try {
            return gameDAO.getGamesCount(email,startDate,endDate);
        } catch (InvalidIDException e) {
            throw new RuntimeException(e);
        }
    }

    //根据日期限定，用户名，页数限定条件查询对局
    @Override
    public List<Game> getGamesFromPage(int page, String email, Timestamp startDate, Timestamp endDate) throws NoSuchPageException {
        if (page < 1 || page > getGamePagesCount()) {
            throw new NoSuchPageException();
        }
        int start=(page-1)*20;
        //确定查询的对局数，如果剩余的对句数多余等于20就查询20条，如果少于20条就查询剩余的对局数
        int end=gameDAO.getGamesCount()-start;
        if(end>=20){
            end=20;
        }
        return gameDAO.getGamesFromPageDate(start,end, email, startDate, endDate);
    }

    //根据用户名，页数限定条件查询对局
    @Override
    public List<Game> getGamesFromPage(int page, int userID) throws InvalidIDException, NoSuchPageException {
        if (page < 1 || page > getGamePagesCount()) {
            throw new NoSuchPageException();
        }
        int start=(page-1)*20;
        //确定查询的对局数，如果剩余的对句数多余等于20就查询20条，如果少于20条就查询剩余的对局数
        int end=gameDAO.getGamesCount()-start;
        if(end>=20){
            end=20;
        }
        return gameDAO.getGamesFromPage(start,end, userID);
    }

    //根据时间，页数限定条件查询对局，查询全部，用户名为0
    @Override
    public List<Game> getGamesFromPage(int page, Timestamp startDate, Timestamp endDate) throws NoSuchPageException {
        if (page < 1 || page > getGamePagesCount()) {
            throw new NoSuchPageException();
        }
        int start=(page-1)*20;
        //确定查询的对局数，如果剩余的对句数多余等于20就查询20条，如果少于20条就查询剩余的对局数
        int end=gameDAO.getGamesCount()-start;
        if(end>=20){
            end=20;
        }
        return gameDAO.getGamesFromPageDate(start,end, "", startDate, endDate);
    }

    //根据页数限定条件查询对局，查询全部，用户名为0
    @Override
    public List<Game> getGamesFromPage(int page) throws NoSuchPageException {
        if (page < 1 || page > getGamePagesCount()) {
            throw new NoSuchPageException();
        }
        int start=(page-1)*20;
        //确定查询的对局数，如果剩余的对句数多余等于20就查询20条，如果少于20条就查询剩余的对局数
        int end=gameDAO.getGamesCount()-start;
        if(end>=20){
            end=20;
        }
        return gameDAO.getGamesFromPage(start,end, 0);
    }

    //根据用户名userID限定条件查找第一页中的对局
    @Override
    public List<Game> getRecentGamesOfUser(int userID) throws InvalidIDException {
        //确定查询的对局数，如果剩余的对句数多余等于20就查询20条，如果少于20条就查询剩余的对局数
        int end=gameDAO.getGamesCount(userID);
        if(end>=10){
            end=10;
        }
        return gameDAO.getGamesFromPage(0,end, userID);
    }

    @Override
    public int getUserDisplayedGamePagesCount(int userID) {
        return (displayedGameDAO.getUserDisplayedGamesCount(userID) + 19) / 20;
    }

    @Override
    public List<GameDisplayInfo> getUserDisplayedGamesFromPage(int userID, int page) throws InvalidIDException, NoSuchPageException {
        if (page < 1 || page > getUserDisplayedGamePagesCount(userID)) {
            throw new NoSuchPageException();
        }
        int start=(page-1)*20;
        int end=gameDAO.getGamesCount()-start;
        if(end>=20){
            end=20;
        }
		return displayedGameDAO.getUserDisplayedGamesFromPage(start,end,userID);//返回了对局的game表中的数据
    }

    @Override
    public boolean getGameDisplayState(int userID, int gameID) throws InvalidIDException {
        return displayedGameDAO.isGameDisplayed(userID,gameID);
    }

    @Override
    public void displayGame(int userID, int gameID, String description) throws InvalidIDException, IllegalOperationException, DuplicatedOperationException {
        // 检查userID和gameID的有效性
        if (userDAO.selectUserbyID(userID)==null || gameDAO.getGame(gameID)==null) {
            throw new InvalidIDException();
        }

        // 检查userID是否是目标对局的参与者
        Game game=gameDAO.getGame(gameID);
        if (game.getUserBlack().getUserID()!=userID&&game.getUserWhite().getUserID()!=userID) {
            throw new IllegalOperationException();
        }

        // 检查目标对局是否已存在于用户的展示页中
        if (displayedGameDAO.isGameDisplayed(userID, gameID)) {
            throw new DuplicatedOperationException();
        }

        // 将对局添加到用户的展示页
        displayedGameDAO.addGameToDisplay(userID, gameID, description);
    }

    @Override
    public void undisplayGame(int userID, int gameID) throws InvalidIDException {
        displayedGameDAO.deletedisplayGame(userID, gameID);//在dispalygame表中删除展示
    }

    @Override
    public boolean switchGameDisplayState(int userID, int gameID) throws InvalidIDException {
        if(displayedGameDAO.isGameDisplayed(userID,gameID)){
            displayedGameDAO.deletedisplayGame(userID,gameID);
            return false;
        }
        else{
            displayedGameDAO.addGameToDisplay(userID,gameID,"");
            return true;
        }
    }
}
